﻿namespace MSSqlSchemaDoc.Provider.MicrosoftSqlServer
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Data;
    using MSSqlSchemaDoc.Core.DataStructures;

    /// <summary>
    /// Contains scripting helper methods for foreign keys.
    /// </summary>
    public partial class SqlScriptingManager
    {
        /// <summary>
        /// Adds the foreign key reference data to a column.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="foreignKeyData">The foreign key data.</param>
        private static void AddForeignKeyConstraintsForColumn(Column column, DataTable foreignKeyData)
        {
            if (foreignKeyData == null)
            {
                return;
            }

            // Build list of existing foreign key constraints
            List<string> fks = new List<string>();

            if (column.ForeignKeyReferences != null)
            {
                foreach (ForeignKeyReference fkr in column.ForeignKeyReferences)
                {
                    fks.Add(fkr.ConstraintName);
                }
            }

            for (int i = 0; i < foreignKeyData.Rows.Count; i++)
            {
                DataRow row = foreignKeyData.Rows[i];

                if (row.Field<int>("ReferencedObjectId") == column.ParentObjectId
                    && row.Field<int>("ReferencedColumnId") == column.ColumnId)
                {
                    string name = row.Field<string>("ObjectName");
                    if (!fks.Contains(name))
                    {
                        if (column.ForeignKeyReferences == null)
                        {
                            column.ForeignKeyReferences = new Collection<ForeignKeyReference>();
                        }

                        ForeignKeyReference keyref = new ForeignKeyReference();
                        keyref.ConstraintName = name;

                        column.ForeignKeyReferences.Add(keyref);
                    }
                }
            }
        }

        /// <summary>
        /// Adds the foreign key data to a table.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="foreignKeyData">The foreign key data.</param>
        private static void AddForeignKeyContraintsForTable(Table table, DataTable foreignKeyData)
        {
            table.ForeignKeys = new Collection<ForeignKey>();

            for (int i = 0; i < foreignKeyData.Rows.Count; i++)
            {
                DataRow row = foreignKeyData.Rows[i];
                int foreignKeyId = row.Field<int>("ObjectId");

                if (row.Field<int>("ReferencingTableId") == table.ObjectId)
                {
                    ForeignKey fk = new ForeignKey();

                    fk.Name = row.Field<string>("ObjectName");
                    fk.IsDisabled = row.Field<bool>("IsDisabled");
                    fk.IsNotForReplication = row.Field<bool>("IsNotForReplication");
                    fk.IsNotTrusted = row.Field<bool>("IsNotTrusted");
                    fk.DeleteReferentialActionDescription = row.Field<string>("DeleteReferentialActionDescription");
                    fk.UpdateReferentialActionDescription = row.Field<string>("UpdateReferentialActionDescription");
                    fk.IsSystemNamed = row.Field<bool>("IsSystemNamed");

                    fk.Columns = new Collection<ForeignKeyColumnPair>();

                    do
                    {
                        row = foreignKeyData.Rows[i];

                        ForeignKeyColumnPair pair = new ForeignKeyColumnPair();
                        pair.ReferencedColumnId = row.Field<int>("ReferencedColumnId");
                        pair.ReferencedColumnName = row.Field<string>("ReferencedColumnName");
                        pair.ReferencingColumnId = row.Field<int>("ReferencingColumnId");
                        pair.ReferencingColumnName = row.Field<string>("ReferencingColumnName");
                        pair.ReferencedTableName = row.Field<string>("ReferencedTableName");

                        fk.Columns.Add(pair);
                        i++;
                    }
                    while (
                        i < foreignKeyData.Rows.Count
                        && foreignKeyData.Rows[i].Field<int>("ReferencingTableId") == table.ObjectId
                        && foreignKeyId == foreignKeyData.Rows[i].Field<int>("ObjectId"));

                    i--;
                    table.ForeignKeys.Add(fk);
                }
            }
        }
    }
}
